/*! Texture and Render Target interface implementation for Direct3D 11

@author Sergio J. de los Santos
*/
#include "stdafx.h"

#include "Texture.h"

using namespace std;

/*! Constructor

@param pGraphicDevice	Crush Graphic Device version D3D11
@param pd3dDevice		Direct3D11 Device
*/
TextureD3D11::TextureD3D11(ID3D11Device* pd3dDevice)
{
	m_pd3dDevice				= pd3dDevice;
	m_pd3dTexture				= NULL;
	m_pd3dResourceView			= NULL;
}

//! Destructor
TextureD3D11::~TextureD3D11( )
{
	Destroy();
}

//! Destroy
void TextureD3D11::Destroy()
{
	_SAFE_RELEASE(m_pd3dTexture);
	_SAFE_RELEASE(m_pd3dResourceView);
}



/*! Carga la textura desde un archivo

@param strFileName	Nombre de la textura
@param pTexDesc		Descriptor de la textura a crear (es opcional)
@returns true si la cargo, false si fallo
*/
bool TextureD3D11::CreateFromFile(const string& strFileName)
{
	D3DX11_IMAGE_LOAD_INFO loadInfo;
	loadInfo.Width			= D3DX11_DEFAULT;
	loadInfo.Height			= D3DX11_DEFAULT;
	loadInfo.Depth			= D3DX11_DEFAULT;
	loadInfo.FirstMipLevel	= 0;
	loadInfo.MipLevels		= D3DX11_DEFAULT;
	loadInfo.Usage			= (D3D11_USAGE) D3DX11_DEFAULT;
	loadInfo.BindFlags		= D3D11_BIND_SHADER_RESOURCE;
	loadInfo.CpuAccessFlags = 0;
	loadInfo.MiscFlags		= 0;
	loadInfo.Format			= DXGI_FORMAT_FROM_FILE;
	loadInfo.Filter			= D3DX11_FILTER_TRIANGLE;
	loadInfo.MipFilter		= D3DX11_FILTER_TRIANGLE;
	loadInfo.pSrcInfo		= NULL;

	HRESULT hr = S_OK;

	D3DX11_IMAGE_INFO imgInfo;
	hr = D3DX11GetImageInfoFromFileA(strFileName.data(), NULL, &imgInfo, NULL);
	if(FAILED(hr))
		return false;

	m_dxgiFormat	= imgInfo.Format;

	D3DX11_IMAGE_LOAD_INFO* pLoadInfo = NULL;

	if(imgInfo.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE && imgInfo.ArraySize == 6)
	{
		loadInfo.Width			= imgInfo.Width;
		loadInfo.Height			= imgInfo.Height;
		loadInfo.Depth			= imgInfo.Depth;
		loadInfo.Format			= imgInfo.Format;
		loadInfo.MiscFlags 		= imgInfo.MiscFlags;
		loadInfo.FirstMipLevel	= 0;
		loadInfo.pSrcInfo	= &imgInfo;
		pLoadInfo = &loadInfo;

		// Si quiero un CubeMap y el Array Size no es de 6 entonces la textura no puede ser CubeMap
		if(imgInfo.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE && imgInfo.ArraySize != 6 )
			return false;
	}


	// Load the Texture
	hr = D3DX11CreateShaderResourceViewFromFileA(m_pd3dDevice, strFileName.data(), pLoadInfo, NULL, &m_pd3dResourceView, NULL);
	if(FAILED(hr))
		return false;
	
	ID3D11Texture2D* pd3dTexture = NULL;
	m_pd3dResourceView->GetResource((ID3D11Resource**)&pd3dTexture);
	if(pd3dTexture)
	{
		pd3dTexture->GetDesc(&m_texDescriptor);
		_SAFE_RELEASE(pd3dTexture);
	}
	return true;
}




/*! Create a Texture Render Target

@param rtDesc	Descriptor con las caracteristicas del render target
@param strName	Nombre del recurso
@returns true if ok else false
*/
bool TextureD3D11::Create(const D3D11_TEXTURE2D_DESC& texInfo)
{
	m_texDescriptor	= texInfo;

	if(m_texDescriptor.ArraySize > 1)
		return CreateTextureArray();
	return false;
}

/*! 

@returns true if ok else false
*/
bool TextureD3D11::CreateTextureArray()
{
	HRESULT hr = m_pd3dDevice->CreateTexture2D(&m_texDescriptor, NULL, (ID3D11Texture2D**)&m_pd3dTexture);
	if(FAILED(hr))	
		return false;

	ZeroMemory(&m_srViewDesc, sizeof(m_srViewDesc));
	
	// Shader Resource View
	m_srViewDesc.Format							= m_texDescriptor.Format;	
	m_srViewDesc.ViewDimension					= D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
	m_srViewDesc.Texture2DArray.MipLevels		= m_texDescriptor.MipLevels;
	m_srViewDesc.Texture2DArray.MostDetailedMip	= 0;
	m_srViewDesc.Texture2DArray.ArraySize		= m_texDescriptor.ArraySize;
	m_srViewDesc.Texture2DArray.FirstArraySlice	= 0;

	hr = m_pd3dDevice->CreateShaderResourceView( m_pd3dTexture, &m_srViewDesc, &m_pd3dResourceView );
	if( FAILED(hr) )
		return false;

#ifdef DEBUG
	const char szName[] = "TextureArray";
	m_pd3dResourceView->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( szName ) - 1, szName );
#endif 
	return true;
}



/*! 

@returns true if ok else false
*/
bool TextureD3D11::LoadTextureOnArray(ID3D11DeviceContext* pd3dContext, int slice, const string& filename)
{
	D3DX11_IMAGE_LOAD_INFO loadInfo;
	ZeroMemory( &loadInfo, sizeof( D3DX10_IMAGE_LOAD_INFO ) );
	loadInfo.Width			= m_texDescriptor.Width;
	loadInfo.Height			= m_texDescriptor.Height;
	loadInfo.Depth			= 1;
	loadInfo.FirstMipLevel	= 0;
	loadInfo.MipLevels		= m_texDescriptor.MipLevels;
	loadInfo.Usage			= D3D11_USAGE_STAGING;
	loadInfo.BindFlags		= 0;
	loadInfo.CpuAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
	loadInfo.MiscFlags		= 0;
	loadInfo.Format			= m_texDescriptor.Format;
	loadInfo.Filter			= D3DX11_FILTER_NONE;
	loadInfo.MipFilter		= D3DX11_FILTER_NONE;

	ID3D11Texture2D* pd3dTexture = NULL;
	HRESULT hr = D3DX11CreateTextureFromFileA(m_pd3dDevice, filename.c_str(), &loadInfo, NULL, (ID3D11Resource**)&pd3dTexture, NULL);
	if(FAILED(hr))
		return false;

	UINT uiMipCount			= m_texDescriptor.MipLevels;

	for(UINT i = 0; i < uiMipCount; i++)
	{
		D3D11_MAPPED_SUBRESOURCE mappedTex2D;

		UINT uiSrcSubResource = D3D11CalcSubresource(i, 0, uiMipCount);

		pd3dContext->Map(pd3dTexture, uiSrcSubResource, D3D11_MAP_READ, 0, &mappedTex2D );

		UINT uiDstSubResource	= D3D11CalcSubresource(i, slice, uiMipCount);
		pd3dContext->UpdateSubresource(m_pd3dTexture, uiDstSubResource, NULL, mappedTex2D.pData, mappedTex2D.RowPitch, 0);

		pd3dContext->Unmap(pd3dTexture, uiSrcSubResource);

	}

	_SAFE_RELEASE(pd3dTexture);
	return true;
}

/*! 

@returns true if ok else false
*/
//bool TextureD3D11::UpdateFromDDS(IRenderContext* pContext, const UpdateInfo& ui, Buffer::SP spBufferDDS)
//{
//	RenderContextD3D11*		pRenderContextD3D11 = (RenderContextD3D11*)pContext;
//	ID3D11DeviceContext*	pd3dContext			=  pRenderContextD3D11->GetDeviceContext();
//
//
//	D3DX11_IMAGE_LOAD_INFO loadInfo;
//	ZeroMemory( &loadInfo, sizeof( D3DX10_IMAGE_LOAD_INFO ) );
//	loadInfo.Width			= ui.width;
//	loadInfo.Height			= ui.height;
//	loadInfo.Depth			= D3DX_FROM_FILE;
//	loadInfo.FirstMipLevel	= 0;
//	loadInfo.MipLevels		= m_texDescriptor.GetMipmapCount();
//	loadInfo.Usage			= D3D11_USAGE_STAGING;
//	loadInfo.BindFlags		= 0;
//	loadInfo.CpuAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
//	loadInfo.MiscFlags		= 0;
//	loadInfo.Format			= m_dxgiFormat;
//	loadInfo.Filter			= D3DX11_FILTER_NONE;
//	loadInfo.MipFilter		= D3DX11_FILTER_NONE;
//
//	ID3D11Texture2D* pd3dTexture = NULL;
//	HRESULT hr = D3DX11CreateTextureFromMemory(m_pd3dDevice, spBufferDDS->GetBuffer(), spBufferDDS->GetSize(), &loadInfo, NULL, (ID3D11Resource**)&pd3dTexture, NULL);
//	if(FAILED(hr))
//		return false;
//	
//	UINT uiMipCount			= m_texDescriptor.GetMipmapCount();
//
//	for(UINT i = 0; i < uiMipCount; i++)
//	{
//		D3D11_MAPPED_SUBRESOURCE mappedTex2D;
//
//		UINT uiSrcSubResource = D3D11CalcSubresource(i, 0, uiMipCount);
//
//		pd3dContext->Map(pd3dTexture, uiSrcSubResource, D3D11_MAP_READ, 0, &mappedTex2D );
//
//		UINT uiDstSubResource	= D3D11CalcSubresource(i, ui.slice, uiMipCount);
//		pd3dContext->UpdateSubresource(m_pd3dTexture, uiDstSubResource, NULL, mappedTex2D.pData, mappedTex2D.RowPitch, 0);
//
//		pd3dContext->Unmap(pd3dTexture, uiSrcSubResource);
//
//	}
//
//	_SAFE_RELEASE(pd3dTexture);
//	return true;
//}



/*! 

@returns true if ok else false
*/
bool TextureD3D11::CreateFromRAW(const D3D11_TEXTURE2D_DESC& texInfo, void* pData)
{
	m_texDescriptor	= texInfo;
	m_dxgiFormat	= texInfo.Format;

	// Make Array of subresource data
	D3D11_SUBRESOURCE_DATA	subResourcesData;

	uint32		uiPitch		= texInfo.Width;

	subResourcesData.pSysMem			= pData;
	subResourcesData.SysMemPitch		= uiPitch;
	subResourcesData.SysMemSlicePitch	= 0;
	
	HRESULT hr = m_pd3dDevice->CreateTexture2D(&m_texDescriptor, &subResourcesData, (ID3D11Texture2D**)&m_pd3dTexture);
	if(FAILED(hr))	
		return false;

	// Create the render target view
	ZeroMemory(&m_srViewDesc, sizeof(m_srViewDesc));

	// Shader Resource View
	m_srViewDesc.Format				= m_texDescriptor.Format;	// Make the shaders see this as R32_FLOAT instead of typeless
	m_srViewDesc.ViewDimension		= D3D11_SRV_DIMENSION_TEXTURE2D;
	m_srViewDesc.Texture2D.MipLevels = 1;
	m_srViewDesc.Texture2D.MostDetailedMip = 0;
	hr = m_pd3dDevice->CreateShaderResourceView( m_pd3dTexture, &m_srViewDesc, &m_pd3dResourceView );
	if( FAILED(hr) )
		return false;

#ifdef DEBUG
	const char szName[] = "TextureFromRAW";
	m_pd3dResourceView->SetPrivateData( WKPDID_D3DDebugObjectName, sizeof( szName ) - 1, szName );
#endif 

	return true;
}

